/* INCLUDES ************************************************************/
/* 1. C文件同名头文件，优先位置 ****************************************/

/* 2. C系统文件 ********************************************************/


/* 3. 其他库的 .h 文件 *************************************************/


/* 4. 本项目内 .h 文件 *************************************************/
#include "uni_hal_mailbox.h"
#include "mailbox.h"
#include <rtthread.h>

/* 宏定义 **************************************************************/
/* 格式为全部大写，用“_”作为连字符 ***********************************/
#define MAILBOX_PRINT(format, ...)  //rt_kprintf("%s %d:"format, __FUNCTION__, __LINE__, ##__VA_ARGS__)

/* 类型定义 ************************************************************/
typedef struct{
	mailbox_serial_number_t number;	
	mailbox_callback_t callback;
	char *args;
}mailbox_register_callback_t;

mailbox_register_callback_t mailbox_register_callback[MAILBOX_MAX];



/* static 变量定义 *****************************************************/
static rt_mutex_t s_mailbox_mutex = NULL;


/* global 变量定义 *****************************************************/


/* extern 变量声明 *****************************************************/


/* static 函数声明 *****************************************************/
static rt_mq_t s_mailbbox_queue = NULL;

#if HIFI_MOCK_TEST
#define KWS_RESULT_616_ADDR     (0x7ffe0000 + (64 * 1024) + (3 * 1024))
#define KWS_RESULT_616_SIZE     (1024)
#define READ_FLASH_ADDR         (KWS_RESULT_616_ADDR + KWS_RESULT_616_SIZE)
#define READ_FLASH_SIZE         (1024 * 2)
#define SEND_RECORD_ADDR        (READ_FLASH_ADDR + READ_FLASH_SIZE)
#define SEND_RECORD_SIZE        (16 * 16 *2)

static char g_wakeup_result[] = "4239 <s> 你好魔方 </s> \n98.91\n";
static char g_command_result[] = "1239 <s> 打开空调 </s> \n68.91\n";
static int g_wakeup_count = 0;
static int g_watchdog_count = 0;
static int g_is_wakeup = 1;
#endif

/* extern 函数声明 *****************************************************/


/* static 函数定义 *****************************************************/
static void sys_hal_mailbox_thread(void *args)
{
	int ret;
	mailbox_message recv = {0};
	(void)args;
	while(1) {
#if HIFI_MOCK_TEST
    recv.taskId = MAILBOX_NONE;
    rt_thread_mdelay(16);
    if (g_watchdog_count >= 300) {
      g_watchdog_count = 0;
      recv.taskId = MAILBOX_WATCH_DOG_FEED;
      recv.sequenceId = 1;
      recv.size = 0;
    }
    g_watchdog_count++;
    if (g_wakeup_count < 400) {
      g_wakeup_count++;
    }
    if (390 == g_wakeup_count) {
      recv.taskId = MAILBOX_KWS_RESULT;
      recv.sequenceId = 0;
      recv.size = 4;
      recv.data[0] = 100;
      recv.data[1] = 600;
      recv.data[3] = KWS_RESULT_616_SIZE;
      if (g_is_wakeup) {
        recv.data[2] = (int)(void *)g_wakeup_result;
      } else {
        recv.data[2] = (int)(void *)g_command_result;
      }
    }
    if (MAILBOX_NONE == recv.taskId) {
      continue;
    }
#else
		MAILBOX_PRINT("xQueueReceive\n");
		ret = rt_mq_recv(s_mailbbox_queue, &recv, sizeof(mailbox_message), RT_WAITING_FOREVER);
		MAILBOX_PRINT("xQueueReceive done\n");
		if(RT_EOK != ret) {
			MAILBOX_PRINT("get mailbox queue failed, ret = %d\n", ret);
			continue;
		}
#endif
		MAILBOX_PRINT("recv.taskId: %d\n", recv.taskId);
		MAILBOX_PRINT("recv.size: %d\n", recv.size);
		if(NULL == mailbox_register_callback[recv.taskId].callback) {
			MAILBOX_PRINT("callback =NULL,  recv.taskId = %d\n", recv.taskId);
		}else {
			ret = mailbox_register_callback[recv.taskId].callback(mailbox_register_callback[recv.taskId].args, &recv);	
			if(0 != ret) {
				MAILBOX_PRINT("mailbox func failed, recv.taskId = %d, ret = %d\n", recv.taskId, ret);
			}
		}
	}
	rt_mq_delete(s_mailbbox_queue);
}

static void sys_hal_mailbox_handler(void * args)
{
	int ret;
	mailbox_message message;
	u32 mailbox_reg;
	u32 value;
	(void)args;
	mailbox_reg = MAILBOX_INT_STATUS(MAILBOX_616);
	value = READ(mailbox_reg);
    WRITE(mailbox_reg,value);//clear irq;
	//MAILBOX_PRINT("sys_hal_mailbox_handler, value = %d\n", value);
	if(value & 0x2) //recv irq
	{
		message.sequenceId = READ(MAILBOX_RDDATA(MAILBOX_616));			
		message.taskId = READ(MAILBOX_RDDATA(MAILBOX_616));			
		message.size = READ(MAILBOX_RDDATA(MAILBOX_616));			
		message.data[0] = READ(MAILBOX_RDDATA(MAILBOX_616));			
		message.data[1] = READ(MAILBOX_RDDATA(MAILBOX_616));			
		message.data[2] = READ(MAILBOX_RDDATA(MAILBOX_616));			
		message.data[3] = READ(MAILBOX_RDDATA(MAILBOX_616));			
		message.data[4] = READ(MAILBOX_RDDATA(MAILBOX_616));
		MAILBOX_PRINT("%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\n", \
			message.sequenceId, message.taskId, message.size, message.data[0],\
			message.data[1], message.data[2], message.data[3], message.data[4]);
		ret = rt_mq_send_wait(s_mailbbox_queue, (void *)&message, sizeof(mailbox_message), RT_WAITING_NO);
		if(RT_EOK != ret) {
			MAILBOX_PRINT("put mailbox queue failed, ret = %d\n", ret);
		}
	}else if(value & 0x4){ //err IRQ
		MAILBOX_PRINT("mailbox err happend\n");
	}
	return;
}

/* 外部函数定义 ********************************************************/
int sys_hal_mailbox_register_callback(mailbox_serial_number_t number, mailbox_callback_t mailbox_callback, char *args)
{
	if(number >= MAILBOX_MAX){
		MAILBOX_PRINT("register failed, number = %d\n", number);
		return -1;
	}
	mailbox_register_callback[number].number = number;
	mailbox_register_callback[number].callback = mailbox_callback;
	mailbox_register_callback[number].args = args;
	return 0;
}
int sys_hal_mailbox_send(mailbox_message *message)
{
	int ret;
#if HIFI_MOCK_TEST
  switch (message->taskId) {
    case MAILBOX_KWS_START:
      if (0 == message->data[0]) {
        g_is_wakeup = 1;
      } else {
        g_is_wakeup = 0;
      }
      g_wakeup_count = 0;
      break;
    case MAILBOX_KWS_STOP:
      g_wakeup_count = 391;
      break;
    case MAILBOX_FLASH:
      break;
    default:
      break;
  }
  return 0;
#endif
	if(NULL == s_mailbox_mutex) {
		return -2;
	}
	rt_mutex_take(s_mailbox_mutex, RT_WAITING_FOREVER);
	ret = mailbox_send_msg(message);
	while(ret != 0){
		rt_thread_mdelay(5);	
		ret = mailbox_send_msg(message);
	}
	rt_mutex_release(s_mailbox_mutex);
	return ret;
}
int sys_hal_mailbox_lock(mailbox_lock lock)
{
	return mailbox_sema_lock(lock);
}

int sys_hal_mailbox_unlock(mailbox_lock lock)
{
	mailbox_sema_unlock(lock);
	return 0;
}

int sys_hal_mailbox_is_lock(mailbox_lock lock)
{
	return mailbox_sema_is_lock(lock);
}


int sys_hal_mailbox_init(void)
{
	int ret;
	int i;
	rt_thread_t thread_mailbox;
	for(i = 0; i < MAILBOX_MAX; i ++) {
		mailbox_register_callback[i].number = MAILBOX_NONE;
		mailbox_register_callback[i].args = NULL;
		mailbox_register_callback[i].callback = NULL;
	}
	s_mailbbox_queue = rt_mq_create("queue", sizeof(mailbox_message), MAILBOX_MESSAGE_QUEUE_NUMBER, RT_IPC_FLAG_FIFO);
	if (NULL == s_mailbbox_queue) {
		MAILBOX_PRINT("create mailbox queue failed\n");
		return -1;
	}

		thread_mailbox = rt_thread_create("mailbox", sys_hal_mailbox_thread, NULL, MAILBOX_TASK_STACK, 5, 5);
	if(RT_NULL == thread_mailbox) {
		MAILBOX_PRINT("create mailbox task failed\n");
		if (NULL != s_mailbbox_queue) {
			rt_mq_delete(s_mailbbox_queue);
		}
		return -1;
	}
	
	s_mailbox_mutex = rt_mutex_create("mutex", RT_IPC_FLAG_FIFO);
	ret = mailbox_init(sys_hal_mailbox_handler, MAILBOX_RX_THRESHOLD_VALUE, MAILBOX_TX_THRESHOLD_VALUE, (void *)0);
	
	rt_thread_startup(thread_mailbox);
	return ret;
}

